package com.koron.util;

import com.alibaba.fastjson.JSON;
import com.koron.css2.ApplicationConfig;
import com.koron.util.secret.RequestBean;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.DnsResolver;
import org.apache.http.conn.HttpConnectionFactory;
import org.apache.http.conn.ManagedHttpClientConnection;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.DefaultConnectionReuseStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.DefaultHttpResponseParserFactory;
import org.apache.http.impl.conn.ManagedHttpClientConnectionFactory;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.conn.SystemDefaultDnsResolver;
import org.apache.http.impl.io.DefaultHttpRequestWriterFactory;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.http.HttpStatus;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.util.Base64;
import java.util.concurrent.TimeUnit;

/**
 * 政务服务接口请求工具类
 *
 * @author 杨嘉慧
 * @date 2023/3/3
 */
public class GovServicesReqUtils {

    private static Logger log = LogManager.getLogger(GovServicesReqUtils.class);

    public static String doPostToGovServices(String relativeUrl, Object data) throws Exception {
        RequestBean req = new RequestBean();
        req.setAppid(ApplicationConfig.govServicesAppId);
        req.setData(data);
        String encrypt = getMd5Hex(req);
        req.setSecret(encrypt);
        return doPost(ApplicationConfig.govServicesPrefUrl + relativeUrl, req, 15000);
    }

    private static String getMd5Hex(RequestBean bean) throws Exception {
        return encode3Des(ApplicationConfig.govServicesKey,System.currentTimeMillis() + "_" + DigestUtils.md5Hex(bean.toJson()));
    }

    private static String encode3Des(String key,String srcStr) throws Exception {
        if (key.getBytes().length < 24) {
            throw new Exception("密码长度不能小于24个字符");
        }
        byte[] src = srcStr.getBytes();
        // 生成密钥
        SecretKey deskey = new SecretKeySpec(key.getBytes(), "DESede");
        // 加密
        Cipher c1 = Cipher.getInstance("DESede");
        c1.init(Cipher.ENCRYPT_MODE, deskey);

        String pwd = Base64.getEncoder().encodeToString(c1.doFinal(src));
        return pwd;
    }

    /**
     * 通发送POST请求
     *
     * @param data    请求体参数
     * @param url     请求的url
     * @param timeout 设置的超时时间, 单位为毫秒
     * @return json格式的的响应体字符串
     */
    private static String doPost(String url, Object data, int timeout) {
        CloseableHttpResponse response = null;
        try {
            StringEntity entity = new StringEntity(JSON.toJSONString(data), "UTF-8");
            HttpPost httppost = new HttpPost(url);

            httppost.addHeader("accept", "application/json");
            httppost.addHeader("Charset", "UTF-8");
            httppost.addHeader("Content-Type", "application/json; charset=UTF-8");
            int defaultTimeOut = 15000;
            if (timeout > 0) {
                defaultTimeOut = timeout;
            }
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(timeout)
                    .setConnectionRequestTimeout(600000).setSocketTimeout(600000).build();
            httppost.setConfig(requestConfig);
            log.debug("post url is " + url + ".");
            httppost.setEntity(entity);
            CloseableHttpClient httpclient = getHttpClient();
            response = httpclient.execute(httppost);
            int status = response.getStatusLine().getStatusCode();
            if (status == HttpStatus.OK.value()) {
                return EntityUtils.toString(response.getEntity(), "utf-8");
            } else {
                String error = EntityUtils.toString(response.getEntity(), "utf-8");
                log.error("请求url: " + url);
                log.error("请求参数：" + data);
                log.error(error);
                throw new RuntimeException(error);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (null != response) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
    }

    private static PoolingHttpClientConnectionManager manager = null;
    private static CloseableHttpClient httpClient = null;

    private static synchronized CloseableHttpClient getHttpClient() {
        if (httpClient == null) {
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.INSTANCE)
                    .register("https", SSLConnectionSocketFactory.getSystemSocketFactory()).build();
            HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connectionFactory = new ManagedHttpClientConnectionFactory(
                    DefaultHttpRequestWriterFactory.INSTANCE, DefaultHttpResponseParserFactory.INSTANCE);
            DnsResolver dnsResolver = SystemDefaultDnsResolver.INSTANCE;
            manager = new PoolingHttpClientConnectionManager(socketFactoryRegistry, connectionFactory, dnsResolver);
            SocketConfig defaultSocketConfig = SocketConfig.custom().setTcpNoDelay(true).build();
            manager.setDefaultSocketConfig(defaultSocketConfig);
            manager.setMaxTotal(500);
            manager.setDefaultMaxPerRoute(200);
            manager.setValidateAfterInactivity(5 * 1000);
            RequestConfig defaultRequestConfig = RequestConfig.custom().setConnectTimeout(2 * 1000)
                    .setSocketTimeout(5 * 1000)
                    .setConnectionRequestTimeout(2000)
                    .build();
            httpClient = HttpClients.custom().setConnectionManager(manager).setConnectionManagerShared(false)
                    .evictIdleConnections(1, TimeUnit.MINUTES)
                    .evictExpiredConnections()
                    .setConnectionTimeToLive(1, TimeUnit.MINUTES)
                    .setDefaultRequestConfig(defaultRequestConfig)
                    .setConnectionReuseStrategy(DefaultConnectionReuseStrategy.INSTANCE)
                    .setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE)
                    .setRetryHandler(new DefaultHttpRequestRetryHandler(0, false))
                    .build();
            Runtime.getRuntime().addShutdownHook(new Thread() {
                @Override
                public void run() {
                    try {
                        httpClient.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        return httpClient;
    }
}
